<!--
 * @Author: 宏联-vision java_hongwx@163.com
 * @Date: 2025-04-07 08:26:29
 * @LastEditors: liyin 2179253556@qq.com
 * @LastEditTime: 2025-08-29 17:32:57
 * @FilePath: Index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
    <div class="faceHomeBox" ref="homeRef" :style="'transform:scale(' +
        scaleValue +
        ') translate(-50%,-50%)  translateZ(0)  translate3d(0,0,0)'
        ">
        <!-- 加载层 -->
        <div class="loading-view-box" v-show="showLoading">
            <breeding-rhombus-spinner style="margin-bottom: 30px;" :animation-duration="3000" :size="100"
                color="#409EFF" />
            正在努力加载中，请稍后...
        </div>
        <!-- 顶部图标 -->
        <Header ref="header"></Header>
        <!-- 主内容 -->
        <div class="screenBox" :style="{ height: screenBoxHeight + 'px' }">
            <div class="screenLeft" ref="screenLeftRef">
                <div ref="screenLeftTopRef">
                    <screenLeftOne ref="screenLeftOneRef" :startDate="pageQuery.default_startDate"
                        :verify_code="verify_code" :endDate="pageQuery.default_endDate">
                    </screenLeftOne>
                    <screenLeftTwo ref="screenLeftTwoRef" :startDate="pageQuery.default_startDate"
                        :verify_code="verify_code" :endDate="pageQuery.default_endDate">
                    </screenLeftTwo>
                </div>
                <screenLeftThird ref="screenLeftThirdRef" :screenLeftThirdHeight="screenLeftThirdHeight"
                    :verify_code="verify_code">
                </screenLeftThird>
            </div>
            <div class="screenCenter">
                <screenCenterOne ref="screenCenterOneRef" :startDate="pageQuery.default_startDate"
                    :endDate="pageQuery.default_endDate" :verify_code="verify_code">
                </screenCenterOne>
                <screenCenterTwo ref="screenCenterTwoRef" :screenCenterTwoHeight="screenCenterTwoHeight"
                    :verify_code="verify_code">
                </screenCenterTwo>
            </div>
            <div class="screenRight" ref="screenRightRef">
                <Title>
                    <template #title>
                        学校缴费详细统计与套餐办理分析
                    </template>
                    <template #info>
                        <el-button style="display: flex;align-items: center;" type="text" size="mini"
                            @click="showDialog">
                            <el-icon color="#00FCFF">
                                <QuestionFilled />
                            </el-icon>
                            <span style="color: #00FCFF;">查看全局说明</span>
                        </el-button>
                    </template>
                </Title>
                <div class="rtContentBox" :style="{ height: rtContentBoxHeight + 'px' }">
                    <!-- 加载层 -->
                    <div class="loading-view-box" v-show="showLoading2">
                        <breeding-rhombus-spinner style="margin-bottom: 30px;" :animation-duration="3000" :size="100"
                            color="#409EFF" />
                        正在努力加载中，请稍后...
                    </div>
                    <screenRtOne ref="screenRtOneRef" :startDate="pageQuery.startDate" :endDate="pageQuery.endDate"
                        @selectItem="selectItem"></screenRtOne>
                    <screenRtTwo ref="screenRtTwoRef" :screenRtTwoHeight="screenRtTwoHeight" :isNodate="isNodate"
                        :startDate="pageQuery.startDate" :endDate="pageQuery.endDate"></screenRtTwo>
                </div>
            </div>
        </div>
        <!-- 主内容区 -->
        <Footer ref="footer"></Footer>
        <div class="dialog-box" v-if="dialogVisible" ref="dialogBoxRef"
            :style="{ top: dialogTop + 'px', left: dialogLeft + 'px' }" @mousedown="startDrag">
            <div class="close-img-box">
                <el-image :src="closeImg" @click.stop="dialogVisible = false"></el-image>
            </div>
            <div class="contentInfo">
                <div class="title">默认统计时间：</div>
                <div class="data">{{ pageQuery.default_startDate }} ~ {{ pageQuery.default_endDate }} <span
                        style="margin-left: 10px;">数据刷新时间：一分钟</span></div>
                <div class="title">名称解析：</div>
                <div>
                    <p><span>学生总数量&新生总数量：</span>来源于人员中心有效学生数量；</p>
                    <p><span>缴费总额/缴费总数：</span>缴费订单总额/总数，包含待转入的；</p>
                    <p><span>总办理率：</span>缴费总数/学生总数；</p>
                    <p><span>新生缴费额/新生缴费数：</span>{{ nowGrade }}级缴费订单总额/总数；</p>
                    <p><span>新生办理率：</span>新生缴费数/新生总数；</p>
                    <p><span>续办总额/续办数：</span>续办额/续办数：之前存在缴费订单的学生，再次缴费的订单总额;</p>
                    <p><span>续办率：</span>续费数/缴费总数：</p>
                    <p><span>退款金额/退款数：</span>退款订单总额/总数；</p>
                    <p><span>退款率：</span>退款数/缴费总数</p>
                    <p><span>待转入总额/待转入总数：</span>缴费成功但未转入，转入失败的订单总额/总数</p>
                </div>
            </div>
        </div>
    </div>
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router'
import { BreedingRhombusSpinner } from 'epic-spinners'
import { ElMessage } from 'element-plus'
import Header from './Common/Header.vue'
import Footer from './Common/Footer.vue'
import screenLeftOne from './screenLeftOne.vue'
import screenLeftTwo from './screenLeftTwo.vue'
import screenLeftThird from './screenLeftThird.vue'
import screenCenterOne from './screenCenterOne.vue'
import screenCenterTwo from './screenCenterTwo.vue'
import screenRtOne from './screenRtOne.vue'
import screenRtTwo from './screenRtTwo.vue'
import $util from "../util/util"
import closeImg from '../assets/images/icon_close@2x.png'
import { ref, onMounted, onUnmounted, reactive, nextTick, watch } from "vue"
import { paymentBIConfig, schoolStatistic } from './Options/Api'
import { PiniaStore } from '../store/index'
const scaleValue = ref<any>('')
const route = useRoute()
const dialogVisible = ref<any>(false)
const store = PiniaStore()
const showLoading = ref<boolean>(false)
const showLoading2 = ref<boolean>(false)
const pageQuery = reactive<any>({
    schoolId: '', // 学校ID
    startDate: '', // 开始时间
    endDate: '', // 结束时间
    default_startDate: '', // 默认开始时间
    default_endDate: '', // 默认结束时间
})
const homeRef = ref<any>(null)
const header = ref<any>(null)
const footer = ref<any>(null)
const screenLeftOneRef = ref<any>(null) // 左侧内容区高度
const screenLeftTwoRef = ref<any>(null) // 左侧内容区高度
const screenLeftThirdRef = ref<any>(null) // 左侧内容区高度
const screenLeftTopRef = ref<any>(null) // 左侧内容区高度
const screenCenterOneRef = ref<any>(null) // 主内容区高度
const screenCenterTwoRef = ref<any>(null) // 主内容区高度
const screenRtOneRef = ref<any>(null) // 右侧内容区高度
const screenRtTwoRef = ref<any>(null) // 右侧内容区高度
const screenBoxHeight = ref<number>(0) // 主内容区高度
const screenCenterTwoHeight = ref<number>(0) // 散点图和折线图的高度
const rtContentBoxHeight = ref<number>(0) // 右侧内容区高度
const screenRtTwoHeight = ref<number>(0) // 右侧内容区高度
const screenLeftThirdHeight = ref<number>(0) // 左侧内容区高度
const getHeight = async () => {
    screenBoxHeight.value = homeRef.value.clientHeight - (header.value.$el.clientHeight ? header.value.$el.clientHeight : 0) - (footer.value.$el.clientHeight ? footer.value.$el.clientHeight : 0)
    // 散点图和折线图的高度
    screenCenterTwoHeight.value = screenBoxHeight.value - screenCenterOneRef.value.$el.clientHeight - $util.fontSize(138)
    rtContentBoxHeight.value = screenBoxHeight.value - $util.fontSize(106)
    screenRtTwoHeight.value = rtContentBoxHeight.value - screenRtOneRef.value.$el.clientHeight - $util.fontSize(62)
    // 左侧底部的高度
    screenLeftThirdHeight.value = screenBoxHeight.value - screenLeftTopRef.value.clientHeight - $util.fontSize(122)
}
const setScale = async () => {
    var vw = window.innerWidth / 1920
    var vh = window.innerHeight / 1080
    var scale = vw < vh ? vw : vh
    scaleValue.value = scale
}
const nowGrade = ref<string>('')
// 获取学校列表
const getConfig = async () => {
    const res: any = await paymentBIConfig({
        verify_code: verify_code.value,
    })
    if (res.code !== 1) return ElMessage.error(res.msg)
    pageQuery.startDate = res.data.startDate
    pageQuery.endDate = res.data.endDate
    pageQuery.default_startDate = res.data.startDate
    pageQuery.default_endDate = res.data.endDate
    nowGrade.value = res.data.newGrade
    header.value.getTimes(res.data.server_time)
    screenRtOneRef.value.dataValue = [res.data.startDate, res.data.endDate]
    store.setSchoolList(res.data.schoolList)
}
// 右侧全局的数据
const isNodate = ref<boolean>(true)
const totalInfo = ref<any>({})
const schoolList = ref<any>([])
const getRtInfo = async () => {
    const params = {
        // school_id: pageQuery.schoolId,
        start_date: pageQuery.startDate,
        end_date: pageQuery.endDate,
        verify_code: verify_code.value,
    }
    const res: any = await schoolStatistic(params)
    if (res.code !== 1) {
        return ElMessage.error(res.msg)
    }
    // 使用Promise包装所有后续操作，确保它们全部完成
    return new Promise((resolve) => {
        schoolList.value = res.data.schoolList
        totalInfo.value = res.data.total
        screenRtOneRef.value.setTotalData(JSON.parse(JSON.stringify(totalInfo.value)))
        screenRtOneRef.value.getCharts(res.data.schoolList)
        if (pageQuery.schoolId) {
            // 如果选择了学校
            fliterSchoolData(schoolList.value)
        } else {
            screenRtOneRef.value.setTotalData2(JSON.parse(JSON.stringify(totalInfo.value)))
            // 如果没有选择学校
            if (totalInfo.value.duration_statistic.length !== 0) {
                isNodate.value = false
                let i: number = 0
                let arr: any = []
                Object.keys(totalInfo.value.duration_statistic).forEach((key: any) => {
                    arr.push({
                        name: `${totalInfo.value.duration_statistic[key].duration_name}套餐`,
                        value: totalInfo.value.duration_statistic[key].count,
                        count: totalInfo.value.duration_statistic[key].count,
                        amount: totalInfo.value.duration_statistic[key].amount,
                        rate: totalInfo.value.duration_statistic[key].rate,
                    })
                    i++
                })
                nextTick(() => {
                    screenRtTwoRef.value.initChart(arr)
                    store.setLoddingStatus()
                    resolve(undefined) // 所有操作完成后resolve
                })
            } else {
                isNodate.value = true
                store.setLoddingStatus()
                resolve(undefined) // 所有操作完成后resolve
            }
        }
    })
}
const fliterSchoolData = (list: any) => {
    list.forEach((item: any) => {
        if (Number(item.id) === Number(pageQuery.schoolId)) {
            let arr: any = []
            if (Object.keys(item.duration_statistic).length > 0) {
                isNodate.value = false
                let i: number = 0
                Object.keys(item.duration_statistic).forEach((key: any) => {
                    arr.push({
                        name: `${item.duration_statistic[key].duration_name}套餐`,
                        value: item.duration_statistic[key].count,
                        count: item.duration_statistic[key].count,
                        amount: item.duration_statistic[key].amount,
                        rate: item.duration_statistic[key].rate,
                    })
                    i++
                })
                nextTick(() => {
                    screenRtTwoRef.value.initChart(arr)
                })
            } else {
                isNodate.value = true
            }
            screenRtOneRef.value.setTotalData2(JSON.parse(JSON.stringify(item)))
        }
    })
}
const selectItem = async (params: any, type: string) => {
    pageQuery.schoolId = params.schoolId
    pageQuery.startDate = params.startDate
    pageQuery.endDate = params.endDate
    if (type === 'date') {
        if (params.startDate && params.endDate) {
            showLoading2.value = true
            // 如果选择日期 旧重新请求接口
            await getRtInfo()
            showLoading2.value = false
        }
    } else {
        // 如果切换学校 直接查找相关数据，无需调用接口
        if (params.schoolId) {
            fliterSchoolData(schoolList.value)
        } else {
            screenRtOneRef.value.setTotalData2(JSON.parse(JSON.stringify(totalInfo.value)))
            if (totalInfo.value.duration_statistic.length !== 0) {
                isNodate.value = false
                let i: number = 0
                let arr: any = []
                Object.keys(totalInfo.value.duration_statistic).forEach((key: any) => {
                    arr.push({
                        name: `${totalInfo.value.duration_statistic[key].duration_name}套餐`,
                        value: totalInfo.value.duration_statistic[key].count,
                        count: totalInfo.value.duration_statistic[key].count,
                        amount: totalInfo.value.duration_statistic[key].amount,
                        rate: totalInfo.value.duration_statistic[key].rate,
                    })
                    i++
                })
                nextTick(() => {
                    screenRtTwoRef.value.initChart(arr)
                })
            } else {
                isNodate.value = true
            }
        }
    }
}
// 全局说明拖拽
// 新增拖拽相关变量
const dialogBoxRef = ref<HTMLElement | null>(null)
const dialogTop = ref<any>('50%')
const dialogLeft = ref<any>('50%')
const isDragging = ref(false)
const dragStartX = ref(0)
const dragStartY = ref(0)
const initialTop = ref(0)
const initialLeft = ref(0)

// 开始拖拽
const startDrag = (e: MouseEvent) => {
    if (!dialogBoxRef.value) return

    isDragging.value = true
    dragStartX.value = e.clientX
    dragStartY.value = e.clientY
    initialTop.value = dialogTop.value
    initialLeft.value = dialogLeft.value

    // 添加鼠标移动和释放事件监听
    document.addEventListener('mousemove', handleDrag)
    document.addEventListener('mouseup', stopDrag)

    // 防止文本被选中
    e.preventDefault()
}

// 拖拽中
const handleDrag = (e: MouseEvent) => {
    if (!isDragging.value) return
    const deltaX = e.clientX - dragStartX.value
    const deltaY = e.clientY - dragStartY.value
    dialogTop.value = initialTop.value + deltaY
    dialogLeft.value = initialLeft.value + deltaX
}

// 停止拖拽
const stopDrag = () => {
    isDragging.value = false
    document.removeEventListener('mousemove', handleDrag)
    document.removeEventListener('mouseup', stopDrag)
}

// 计算对话框居中位置
const centerDialog = () => {
    if (!dialogBoxRef.value) return

    const windowWidth = window.innerWidth
    const windowHeight = window.innerHeight
    const dialogWidth = dialogBoxRef.value.offsetWidth
    const dialogHeight = dialogBoxRef.value.offsetHeight

    dialogTop.value = (windowHeight - dialogHeight) / 2
    dialogLeft.value = (windowWidth - dialogWidth) / 2
}

// 监听对话框显示状态变化，显示时居中
const originalDialogVisible = dialogVisible
Object.defineProperty(window, 'dialogVisible', {
    get() { return originalDialogVisible.value },
    set(value) {
        originalDialogVisible.value = value
        if (value) {
            nextTick(() => centerDialog())
        }
    }
})
const showDialog = () => {
    dialogVisible.value = true
    nextTick(() => centerDialog())
}
const timer = ref<any>(null)
const getInnit = async () => {
    await screenLeftTwoRef.value.getList()
    await screenLeftThirdRef.value.getList()
    await screenCenterTwoRef.value.getTransactTime()
    await screenCenterOneRef.value.getList()
    await screenLeftOneRef.value.getList()
    await getRtInfo()
}
const verify_code = ref<any>('')
onMounted(async () => {
    await setScale()
    await getHeight()
    store.setLoddingNum()
    showLoading.value = true
    nextTick(async () => {
        verify_code.value = route.query.verify_code ? route.query.verify_code : ''
        console.log('verify_code', verify_code.value)
        await getConfig()
        await getInnit()
    })
    window.addEventListener('resize', async () => {
        // 计算高度
        setTimeout(async () => {
            await setScale()
            setTimeout(async () => {
                await getHeight()
            }, 400);
        }, 100);
        if (dialogVisible.value && !isDragging.value) {
            centerDialog()
        }
    })
});
// 改进方案：使用递归 setTimeout 确保上一轮完成
const fetchDataPeriodically = async () => {
    try {
        await screenLeftTwoRef.value.getList()
        await screenLeftThirdRef.value.getList()
        await screenCenterOneRef.value.getList()
        await getRtInfo()
        await screenLeftOneRef.value.getList()
        if (Number(store.choiceIndex) === 1) {
            await screenCenterTwoRef.value.getTransactTime()
        } else {
            await screenCenterTwoRef.value.getTransactTimeZheXian()
        }
    } catch (error) {
        console.error('数据获取失败:', error)
    } finally {
        // 确保即使出错也会继续下一次请求
        timer.value = setTimeout(fetchDataPeriodically, 30 * 1000)
    }
}
watch(
    () => store.loddingNum,
    (newValue, oldValue) => {
        if (store.loddingNum === 6) {
            showLoading.value = false
            fetchDataPeriodically() // 启动递归定时器
        }
    },
    { deep: true, immediate: true, }
)
onUnmounted(() => {
    clearTimeout(timer.value)
})
</script>
<style lang="scss" scoped>
.faceHomeBox {
    height: 1080px;
    width: 1920px;
    transform-origin: left top;
    position: absolute;
    left: 50%;
    top: 50%;
    background: url('@/assets/images/bg.png') no-repeat;
    background-size: 100% 100%;
    color: #ffffff;
    transition: all 0.3s ease;
    transform: translate(-50%, -50%) translateZ(0) translate3d(0, 0, 0);

    .loading-view-box {
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0;
        top: 0;
        background-color: rgba($color: #000000, $alpha: 0.7);
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 9;
        color: #409eff;
        flex-direction: column;
    }

    .screenBox {
        width: 100%;
        padding: 20px 40px;
        box-sizing: border-box;
        display: flex;

        .screenLeft {
            width: 500px;
            height: 100%;
            box-sizing: border-box;
            display: inline-block;
            vertical-align: top;
            overflow-y: hidden;
        }

        .screenCenter {
            flex: 1;
            margin: 0 40px;
        }

        .screenRight {
            display: inline-block;
            vertical-align: top;
            width: 500px;
            height: 100%;
            box-sizing: border-box;

            .rtContentBox {
                position: relative;
                margin-top: 24px;
                background: rgba(7, 77, 183, 0.16);
                padding: 20px 20px 0 20px;
            }
        }
    }
}

.dialog-box {
    position: fixed;
    /* 改为fixed定位，使其相对于整个屏幕 */
    width: 620px;
    height: 460px;
    background: #09182F;
    box-shadow: inset 0px 6px 60px 1px #5079FF;
    border-radius: 20px;
    z-index: 99999;
    padding: 0 15px;
    box-sizing: border-box;
    /* 移除margin-top，通过JS计算居中位置 */
    margin: 0;
    background: #09182F;
    box-shadow: inset 0px 6px 60px 1px #5079FF;
    border-radius: 20px;
    z-index: 99999;
    cursor: move;

    /* 显示拖拽光标 */
    .close-img-box {
        position: absolute;
        right: -10px;
        top: -10px;

        .el-image {
            width: 30px;
            cursor: pointer;
        }
    }

    .contentInfo {
        padding: 30px;

        .title {
            font-size: 15px;
            font-weight: bold;
        }

        .data {
            font-size: 14px;
            margin-top: 10px;
            margin-bottom: 15px;
        }

        p {
            font-size: 14px;
            margin: 12px 0;

            span {
                color: #5FD5EC;
            }
        }
    }
}
</style>
